-
Notifications
You must be signed in to change notification settings - Fork 3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add clipboard support #13837
Add clipboard support #13837
Conversation
869d646
to
99e1f27
Compare
Download the artifacts for this pull request: |
|
||
The top-level object itself can be written directly as a shortcut. | ||
|
||
Converting this property to a string will give a JSON representation of all types. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How do you plan to represent image data with this? Base64?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't expect raw image data to appear in the string representation; it'd only be useful to API clients interacting with binary directly (a la screenshot-raw
).
The API in the current form is too simplistic: it will never work with X11 or Wayland. On these platforms, there is no system storage for clipboard data: clipboard is simply an IPC mechanism where X11/Wayland clients listen to data request events, for which the data owning clients respond by sending the data directly to the requesting client via a pipe. Thus the data cannot be freed after a set clipboard call, and an active X11/Wayland connection must be kept open. |
Hmmm, either the clipboard code could statically spawn a thread that keeps running, or these routines could add an mpctx arg. |
I think a separate thread dedicated to clipboard event handling is the only realistic option if the clipboard doesn't live in the VO thread. Getting the clipboard on these platforms has the same problem: X11/Wayland data requesting clients need to listen to data available events, and respond them by reading from a pipe, which can potentially block indefinitely. |
So, it sounds like these routines will want to take a currently-unused mpctx, and when adding linux support, someone will need to add functions that set up and tear down a thread? And the thread can read in clipboard data as it becomes available, and make it available for the Also, does anyone care about firing events on clipboard updates? On macOS, this would require polling (though very low-cost polling; there's an integer |
Rebased with some improvements:
|
AFAIK none of the other platforms require polling: event-based clipboard monitoring is available on Windows, X11, and Wayland. The problem is that on Wayland, this can only be done with the wlr data control extension, which requires KWin or wlroots-based compositors, and is unusable because I think the current policy is to avoid vendor-specific extensions. Otherwise, if the clipboard needs to be usable without a VO, even polling for clipboard updates is practically impossible on Wayland, because only focused windows can get any clipboard contents on Wayland. The only way to do that "headless" is to actually create an invisible 1x1 px popup window just to grab focus and get access to the clipboard, and destroy it immediately after. On tiling WMs this is especially unacceptable. I know this sounds completely idiotic, but this is what @Dudemanguy |
Don't let wayland sucking hold other platforms back. I have no idea how this should work there. Honestly if the only decent way is that specific extension (never looked at it), vendoring it for our purposes is probably fine. |
If this can be done, then it's good news since this means that Windows and Linux can use the same clipboard event monitoring thread approach. Just want to confirm. Although that extension is marked for use by "privileged clients" so I'm not sure if it's OK for mpv to continuously monitor the clipboard in the background. |
int m_clipboard_get(struct MPContext *ctx, struct m_clipboard_item *item); | ||
int m_clipboard_set(struct MPContext *ctx, const struct m_clipboard_item *item); | ||
bool m_clipboard_poll(struct MPContext *ctx); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For Windows and Linux, an event monitoring thread will be used, and data need to be kept alive for Linux, so there needs to be init/uninit functions for the clipboard stuffs so that mpv can clean up the mess when quitting. How about making them take a struct clipboard_ctx
parameter with the init and uninit functions? They don't need to do anything on macOS.
Also on Linux, since this clipboard API is headless and has no VO dependence, it's possible that both X11 and Wayland servers are running, so it requires two separate monitoring threads to handle requests from both window systems. I'm not sure if this means that the API needs a mechanism for multiple clipboard sources.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Re: context, I currently have struct clipboard_state
inited at startup and owned by MPContext
, and it'd be easy enough to add an explicit uninit
at shutdown. I don't think that needs to be added in this PR, though, since nothing in it precludes adding explicit shutdown function later.
Re: X/Wayland, I think we'd want to either have both run continuously (can they run in a single thread, select()
ing both?) and return data from whichever was updated most recently, or have a user setting for which to use (defaulting to whichever we'd use for vo).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can they run in a single thread,
select()
ing both?
It's possible, but it will significantly complicate the implementation. This is especially true for large data transfers on X11, which manifest as a complicated multi-step process, for which the transfer state need to be saved and resumed between calls.
Personally I would like to limit clipboard to 1 backend at a time, to keep it sane. But dynamic switching would need to be implemented, like for VOs. That switching needs to take care of init/uninit on backend switches.
(Side note: not sure about the situation on macOS, but is XQuartz supported by mpv? That would mean that macOS has multiple clipboard backends too.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Personally I would like to limit clipboard to 1 backend at a time, to keep it sane.
Agreed.
I think a reasonable way would be to delegate/marry this to a VO. Then the event loop can be reused to handle the necessary clipboard protocol.
Then add a way to have a global clipboard manager for the sake of win32 and mac (where this doesn't depend on a VO).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think a reasonable way would be to delegate/marry this to a VO. Then the event loop can be reused to handle the necessary clipboard protocol.
Note that win32 also benefits from this: win32 clipboard notification requires a window, so without VO dependence, it is achieved by creating a dummy event-only window and wait for clipboard change messages. If it is delegated to the VO window instead, the window event loop can be reused.
This also provides a reasonable way out for Wayland compositors which don't support the wlr data control protocol.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Microsoft documentation explicitly discourages polling GetClipboardSequenceNumber()
:
Note that this is a not a notification method and should not be used in a polling loop. To be notified when clipboard contents change, use a clipboard format listener or a clipboard viewer.
Although this might not be a problem in practice if mpv does not call the function too frequently.
Also OpenClipboard()
documentation says using NULL
as window causes SetClipboardData
to fail, although several unofficial sources report that it does not fail in practice on win32.
About X/Wayland, I think a vo-based API (using VOCTRL
s) would be the best solution since it solves both the problem of persistent state and Wayland restriction. Although this may have some problems with frequent polling.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, hmm, I'd missed those caveats; m_clipboard_poll
is called on every render loop iteration, so that's probably not the best solution.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this could be worked around by letting the vo monitor clipboard through change events, and on clipboard changes, it runs a command to update a variable in player core, which m_clipboard_poll
checks. This way m_clipboard_poll
does not need to stop the vo thread.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alternately, the vo could monitor clipboard events and fire mp_notify_property
when applicable (might need a dispatch call?), and m_clipboard_poll
could remain a no-op on windows. Not sure if any of this actually implies changes to the API as implemented here at all, then; the vo can just reach into mpctx->clipboard
to hand it a HWND
to pass to OpenClipboard
when performing read/write calls.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The problem is that the current mpv architecture is not designed to make synchronous calls from somewhere down the call hierarchy (vo) to somewhere up (player core). Such usage is a recipe for deadlock: see tech-overview.txt
, "Avoiding callback hell" section. Commands (through input_ctx
) are safe to call from anywhere because they're asynchronous.
As mentioned before, the win32 concerns may be largely theoretical, so the API usage pattern can be the same as macOS. I see no large problem with the current API design for now if X/Wayland handle the clipboard in the vo thread, as there is no special init/uninit functions required.
57136ee
to
1287e5b
Compare
Rebased with minor changes:
I think there are only 2 meaningful known issues left, and I don't think either is a blocker:
Once this merges, there's a decent chance we'll want to add something like this as a built-in script: https://gist.github.com/rcombs/321a3c6b42501290c75cfb3aadf49f63 This allows for bindings like this:
(Also, should we add a way to specify keybinds that use meta on macOS but ctrl elsewhere? Seems useful for default binds.) |
Rebased with changes:
A couple notable caveats to the current API (probably largely macOS-specific):
|
@@ -402,6 +402,12 @@ Remember to quote string arguments in input.conf (see `Flat command syntax`_). | |||
Like all input command parameters, the filename is subject to property | |||
expansion as described in `Property Expansion`_. | |||
|
|||
``screenshot-to-clipboard [<flags>]`` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I definitely see the usefulness but maybe copying images is better left out of the initial implementation to keep it simple first.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Screenshot support is pretty core to this functionality (it's one of, like, 2 main use-cases I'm targeting), so I'm hesitant to remove it unless we have a specific reason.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My thought was that it might be better to have a fleshed-out API for the "copy text/URL(s) to the clipboard" first, merge that and then integrate image clipboards into that (in a different PR). Perhaps even in a way that can be used from the client API.
The top-level object itself can be written directly as a shortcut; the intended | ||
type will be guessed. | ||
|
||
Converting this property to a string will give a JSON representation of all types. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we have any other properties that do this? What's the intended use case for this behavor?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Everything that uses m_property_read_sub
does this (this doesn't use that to avoid reading every clipboard whenever a single one is requested, though maybe I could add a callback feature to m_sub_property
to address that).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The manual doesn't mention this for any other properties so that might be what tripped me up.
|
||
``path`` | ||
A single absolute path to a file on disk. | ||
Exposed for convenience and not included in the top-level map. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So get_property_native("clipboard")
will include text, url and paths yet get_property_string("clipboard/path")
will work?
It doesn't seem wise to introduce such behaviour into properties.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I could include it; it's just redundant with paths
, which would make it a little more annoying to use for development/debugging.
@@ -514,6 +515,10 @@ if not posix and not features['win32-desktop'] | |||
'osdep/terminal-dummy.c') | |||
endif | |||
|
|||
if not features['cocoa'] | |||
sources += files('osdep/clipboard-dummy.c') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The "one global handler" approach will not work on Linux. Both the X11 and Wayland code needs to be compiled in, but only one of them will be active depending on the VO.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd expect to have a single linux implementation of the m_clipboard_*
functions that dispatches between X and Wayland as needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Requiring only one implementation per platform sounds unnecessarily inflexible to me and as you proposed also leads to weird patterns where you have code that only forwards calls. Plus not being able to handle edge cases like X11 on macOS (just an example, not suggesting we should have that).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There can be multiple implementations of the underlying functionality per platform, they just need a implementation of the cross-platform APIs; if e.g. clipboard-linux.c
wants to call into specific routines in clipboard-wayland.c
and clipboard-x11.c
, that's fine.
int m_clipboard_get(struct MPContext *ctx, struct m_clipboard_item *item); | ||
int m_clipboard_set(struct MPContext *ctx, const struct m_clipboard_item *item); | ||
bool m_clipboard_poll(struct MPContext *ctx); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Personally I would like to limit clipboard to 1 backend at a time, to keep it sane.
Agreed.
I think a reasonable way would be to delegate/marry this to a VO. Then the event loop can be reused to handle the necessary clipboard protocol.
Then add a way to have a global clipboard manager for the sake of win32 and mac (where this doesn't depend on a VO).
|
||
#include "clipboard.h" | ||
|
||
int m_clipboard_set(struct MPContext *ctx, const struct m_clipboard_item* item) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also could we use mp_
prefix like with all other things?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not entirely clear on what the style guide situation is for when we use m_
vs mp_
; I see a lot of usage of both within the codebase.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer to use mp_
like we use for everything recently.
FWIW my suggestion stands to add this as a text-only API as first and work on screenshot support in a second step. |
@na-na-hi: Would you be interested in implementing this on other platforms? I ask because you were active in the thread. Let me know if, not. I will put on my backlog instead. I think the consensus on some discussion was that we don't want to merge one platform only code and should implement more backends to it first. |
Yes. My idea is to implement the API on multiple platforms so that it's possible to test for API design issues. At least one from synchronous catagory (Windows/macOS) and one from asynchronous category (X11/Wayland). The initial implementation can be text-only, but the API should be general enough to also cover image formats in the future. |
i added the initial text clipboard support for macOS #15564. please feel free to add the other cases from this PR in another PR. thanks for your effort and getting the ball running on this feature. |
screenshot-to-clipboard
commandclipboard
propertyThis is currently macOS-only; patches welcome for other platforms.